package client;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageFilter;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import ai.MensStrategie;

import spel.Bord;
import spel.Knikker;
import spel.Zet;
/**
 * Jpanel extensie voor het tonen van een speelbord.
 * @author Tim en Stef
 *
 */
public class BordPanel extends JPanel implements MouseListener, MouseMotionListener{
	
	/**
	 *Enumerator om de staat van het Bord aan te geven
	 *
	 */
	public static enum State{NONE,KNIKKER,DRAAI};
	private BufferedImage vakje,knikker,focus;
	private BufferedImage arrowp, arrowm, farrowp, farrowm;
	private int xfocus, yfocus;
	int vaksize;
	Image buffer;
	Graphics bufferg;
	private Knikker[][] knikkers;
	private Map<Knikker, BufferedImage> knikkerplaatjes;
	private State s;
	private MensStrategie m;
	
	private static final File imagedir = new File("img\\");
	
	/**
	 * Initialiseerd een BordPanel.
	 * Laadt ook alle plaatjes in
	 */
	public BordPanel(){
		s = State.NONE;
		m = null;
		knikkerplaatjes = new HashMap<Knikker,BufferedImage>();
		knikkers = new Knikker[Bord.DIM][Bord.DIM];
		for(int i = 0; i<Bord.DIM;i++){
			for(int j = 0; j<Bord.DIM;j++){
				knikkers[i][j] = null;
			}
		}
		try {
			this.addMouseListener(this);
			this.addMouseMotionListener(this);
			File tempfile = new File(imagedir, "vakje.png");
			boolean canread = tempfile.canRead();
			String path = tempfile.getAbsolutePath();
			vakje = ImageIO.read(tempfile);
			knikker = ImageIO.read(new File(imagedir, "knikker.png"));
			focus = ImageIO.read(new File(imagedir,"focus.png"));
			arrowp = ImageIO.read(new File(imagedir,"arrow+.png"));
			arrowm = ImageIO.read(new File(imagedir,"arrow-.png"));
			farrowp = ImageIO.read(new File(imagedir,"arrow+f.png"));
			farrowm = ImageIO.read(new File(imagedir,"arrow-f.png"));
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	/**
	 * Update de Knikkers die het BordPanel laat zien
	 * @param b het Bord dat het BordPanel moet tonen
	 */
	public void updateBord(Bord b){
		for(int i = 0; i<Bord.DIM;i++){
			for(int j = 0; j<Bord.DIM;j++){
				knikkers[i][j] = b.getVeld(i, j).getKnikker();
			}
		}
		this.repaint();
	}
	/**
	 * Methode waarmee het bord getekend wordt
	 */
	@Override
	public void paintComponent(Graphics g) {
		int dimension = this.getWidth();
		if (dimension > this.getHeight()){
			dimension = this.getHeight();
		}
		vaksize = dimension/Bord.DIM;

		buffer = createImage(this.getWidth(),this.getHeight());
		bufferg = buffer.getGraphics();
		
		bufferg.setColor(Color.white);
		bufferg.fillRect(0,0, Bord.DIM*vaksize,Bord.DIM*vaksize);
		bufferg.setColor(Color.black);
		bufferg.fillRect(3*vaksize, 0, 3*vaksize, Bord.DIM*vaksize);
		bufferg.fillRect(0,3*vaksize,  Bord.DIM*vaksize,3*vaksize);
		bufferg.setColor(Color.white);
		bufferg.fillRect(3*vaksize,3*vaksize, 3*vaksize, 3*vaksize);
		for(int i = 0; i < Bord.DIM;i++){
			for(int j = 0; j< Bord.DIM; j++){
				bufferg.drawImage(vakje, i*vaksize, j*vaksize, (i+1)*vaksize,(j+1)*vaksize , 0,0, vakje.getWidth(), vakje.getHeight(), null);
				if(knikkers[i][j]!=null){
					if(!knikkerplaatjes.containsKey(knikkers[i][j])){
						knikkerplaatjes.put(knikkers[i][j], createKnikkerImage(knikker,knikkers[i][j].getKleur()));
					}
					bufferg.drawImage(knikkerplaatjes.get(knikkers[i][j]), i*vaksize,j*vaksize, (i+1)*vaksize,(j+1)*vaksize , 0,0, knikker.getWidth(), knikker.getHeight(), null);
				}
			
			}
		}
		
		//bufferg.drawImage(knikker, 3*vaksize,3*vaksize, (3+1)*vaksize,(3+1)*vaksize , 0,0, knikker.getWidth(), knikker.getHeight(), null);
		if(s==State.KNIKKER)
		bufferg.drawImage(focus, xfocus*vaksize - 2 , yfocus*vaksize - 2 , (xfocus+1)*vaksize + 2 ,(yfocus+1)*vaksize + 2 , 0,0, focus.getWidth(), focus.getHeight(), null);
		
		if(s==State.DRAAI){
			for(int x = 0; x<3; x++){
				for(int y = 0; y<3 ;y++){
					bufferg.drawImage(arrowm, x*3*vaksize, y*3*vaksize, (x*3+1)*vaksize, (y+1)*3*vaksize, 0, 0, arrowm.getWidth(), arrowm.getHeight(), null);
					bufferg.drawImage(arrowp, (x*3 + 2)*vaksize, y*3*vaksize, (x+1)*3*vaksize, (y+1)*3*vaksize, 0, 0, arrowp.getWidth(), arrowp.getHeight(), null);
				}
			}
			if(xfocus%3 == 0){
				int x = xfocus/3;
				int y = yfocus/3;
				bufferg.drawImage(farrowm, x*3*vaksize, y*3*vaksize, (x*3+1)*vaksize, (y+1)*3*vaksize, 0, 0, farrowm.getWidth(), farrowm.getHeight(), null);
			}else if(xfocus%3 == 2){
				int x = xfocus/3;
				int y = yfocus/3;
				bufferg.drawImage(farrowp, (x*3 + 2)*vaksize, y*3*vaksize, (x+1)*3*vaksize, (y+1)*3*vaksize, 0, 0, farrowp.getWidth(), farrowp.getHeight(), null);
			}
			
			
		}
		
		g.drawImage(buffer, 0, 0, null);
		
	}
	/**
	 * Methode die een plaatje van een knikker genereerd op basis van een alphaMap
	 * @param knikker De alphaMap van een knikker
	 * @param c de kleur die het knikker plaatje moet hebben
	 * @return Een Plaatje van een knikker met de kleur c
	 */
	public BufferedImage createKnikkerImage(BufferedImage knikker, Color c){
		BufferedImage fin = new BufferedImage(knikker.getWidth(),knikker.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
		Graphics g = fin.getGraphics();
		g.setColor(c);
		g.fillOval(0,0,(knikker.getWidth(null)),(knikker.getHeight(null)));
		this.applyGrayscaleMaskToAlpha((BufferedImage)fin, (BufferedImage)knikker);		
		return fin;	
	}
	
	/**
	 * Een functie die het alpha kanaal van een plaatje vervangt door de gegeven mask
	 * @param image Het plaatje dat aangepast dient te worden
	 * @param mask Het nieuwe alpha kanaal
	 */
	public void applyGrayscaleMaskToAlpha(BufferedImage image, BufferedImage mask)
	{
	    int width = image.getWidth();
	    int height = image.getHeight();

	    int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);
	    int[] maskPixels = mask.getRGB(0, 0, width, height, null, 0, width);

	    for (int i = 0; i < imagePixels.length; i++)
	    {
	        int color = imagePixels[i] & 0x00ffffff; // Mask preexisting alpha
	        int alpha = maskPixels[i] << 24; // Shift green to alpha
	        imagePixels[i] = color | alpha;
	    }

	    image.setRGB(0, 0, width, height, imagePixels, 0, width);
	}
	
	/**
	 * Methode die bijhoudt wanneer er met de muis wordt geklikt.
	 * Zorgt er vervolgens ook voor dat indien er een Mens speelt de zet wordt doorgegeven
	 */
	@Override
	public void mouseClicked(MouseEvent arg0) {
		Point mousePosition = this.getMousePosition(true);
		if(mousePosition != null){
			int xpos = mousePosition.x/vaksize;
			int ypos = mousePosition.y/vaksize;
			System.out.println("clicked: "+xpos+","+ypos+".");
			if(m!=null){
				if(s == State.KNIKKER){
					m.PlaatsKnikker(xfocus, yfocus);
					s = State.DRAAI;
					this.repaint();
				}else if(s == State.DRAAI){
					int index = (xfocus/3) + (yfocus/3)*3;
					if(xfocus % 3 == 0){
						m.DraaiBord(index, Zet.Richting.Links);
						s = State.NONE;
						this.repaint();
					}else if(xfocus % 3 == 2){
						m.DraaiBord(index, Zet.Richting.Rechts);
						s = State.NONE;
						this.repaint();
					}
				}
			}
		}
	}
	/**
	 * Funtie die het BordPanel zo instelt dat het mogelijk is voor een mens om een zet te doen
	 * @param m de MensStrategie waarvoor de zet moet worden gedaan
	 */
	public void getSet(MensStrategie m){
		this.m = m;
		this.s = State.KNIKKER;
		this.repaint();
	}
	
	/**
	 * Methode om ervoor te zorden dat wanneer de muis het veld verlaar de selectie ook verdwijnt
	 */
	@Override
	public void mouseExited(MouseEvent arg0) {
		xfocus =-1;
		yfocus = -1;
		
	}
	/**
	 * houdt bij boven welk vakje op het BordPanel de muis staat
	 */
	@Override
	public void mouseMoved(MouseEvent e) {
		Point mousePosition = this.getMousePosition(true);
		if(mousePosition != null){
			xfocus = mousePosition.x/vaksize;
			yfocus = mousePosition.y/vaksize;
			this.repaint();
			
		}
		
	}
	/**
	 * stub voor implementatie
	 */
	@Override
	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	/**
	 * stub voor implementatie
	 */
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	/**
	 * stub voor implementatie
	 */
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	/**
	 * stub voor implementatie
	 */
	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
}
